#include "theater.h"
/************************************************
 *
 *  start for regular customer
 *
 ************************************************/

/*  regular customer wait for head customer to have ticket checked */
void waitTickets(int customerId, int groupId)
{
    int temp;
    AcquireLock(lGroup[groupId]);

    /* wait for head customer to tell them the tickets checked */
    /*  if head customer had broadcast, do not wait */
    Printf("Customer [%d] of group [%d] is waiting for the HeadCustomer.\n",customerId,groupId);
    temp=getMV(groupTicket[groupId]);
    if (!temp)
    {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    /* tickets check and go to the next step */
    Printf("Customer [%d] of group [%d] has been told by the HeadCustomer to proceed.\n", customerId, groupId);
    ReleaseLock(lGroup[groupId]);
}

void waitFood(int customerId, int groupId)
{
    int i;
    int temp;
    AcquireLock(lGroup[groupId]);
    temp=getMV(groupAskForFood[groupId]);
    /*  wait for ticketbuyer to ask for if need food */
    if (!temp)
    {
        WaitCV(lGroup[groupId], cGroupFood[groupId]);
    }
    /* random the food request */
    for (i = 0; i < 2; ++i)
    {
        addMVbyValue(groupFoodSum[groupId][i] , answerForFood(i));
    }
    temp=getMV(answerFood[groupId]);
    ++temp;
    setMV(answerFood[groupId],temp);
    /*  tell head customer that they have chosen food */
    if (temp== cr[customerId].groupSize)
    {
        SignalCV(lGroup[groupId], cGroupFood[groupId]);
    }
    /* wait for head customer to get the food */
    /*  if ticketbuyer had broadcast, do not wait */
    Printf("Customer [%d] of group [%d] is waiting for the HeadCustomer.\n",customerId,groupId);
    if (!getMV(groupFood[groupId]))
    {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    /*  after get food, go to the next step */
    Printf("Customer [%d] of group [%d] has been told by the HeadCustomer to proceed.\n", customerId, groupId);
    ReleaseLock(lGroup[groupId]);
}
/* regular customer wait head customer to have the tickets check */
void waitCheck(int customerId, int groupId)
{
    int temp;
    /* DEBUGINFO('c', "Customer [%d] in group [%d] wait check a", customerId, groupId) */;

    AcquireLock(lGroup[groupId]);
    /* DEBUGINFO('c', "Customer [%d] in group [%d] wait check b", customerId, groupId) */;

    /* wait for the head customer to have ticket checked */
    Printf("Customer [%d] of group [%d] is waiting for the HeadCustomer.\n",customerId,groupId);
    temp=getMV(groupCheck[groupId]);
    if (!temp) {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    /* if ticket checked, go to the next step */
    /* DEBUGINFO('c', "Customer [%d] in group [%d] has been told by the HeadCustomer to proceed.", customerId, groupId) */;
    Printf("Customer [%d] of group [%d] has been told by the HeadCustomer to proceed.\n", customerId, groupId);

    ReleaseLock(lGroup[groupId]);

}

/* regular customer wait head customer to tell the seat number */
void waitSeats(int customerId, int groupId) {
    int temp;
    int temp1;
    Customer  * currentCR;
    currentCR = & cr[customerId];
    /* wait for head to get seats */
    AcquireLock(lGroup[groupId]);
    temp=getMV(groupSeat[groupId]);
    if (!temp) {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    temp=getMV(seatPos);
    temp1=getMV(seatLocation[temp]);
    /*  got the seat number from head customer and then info head customer */
    Printf("Customer [%d] in Group [%d] has found the following seat: row [%d] and seat [%d]\n",customerId,groupId,(temp1/MAX_ROW),(temp1%MAX_COL));
    setMV(seatState[temp1],true);
    ++temp;
    setMV(seatPos, temp);
    if (temp == currentCR->groupSize) {
        SignalCV(lGroup[groupId], cGroup[groupId]);
    }
    ReleaseLock(lGroup[groupId]);        
}
void waitLeavingmovieRoom(int customerId, int groupId) {
    int temp;
    AcquireLock(lGroup[groupId]);
    temp=getMV(groupLeaveRoom[groupId]);
    if (!temp) {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    ReleaseLock(lGroup[groupId]);       
}
void waitLeavingTheater(int customerId, int groupId) {
    int temp;
    AcquireLock(lGroup[groupId]);
    temp=getMV(groupLeaveTheater[groupId]);
    if (!temp) {
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }
    ReleaseLock(lGroup[groupId]);       
}


void waitBathroom(int customerId, int groupId) {
    int needBathroom;
    int temp;
    int temp1;
    AcquireLock(lGroup[groupId]);
    temp=getMV(groupAskForBathroom[groupId]);
    if (!temp ){
        WaitCV(lGroup[groupId], cGroup[groupId]);
    }  
    addMV(answerBathroom[groupId]);
    needBathroom=answerForBathroom();
    if(needBathroom){
        /*if want go bathroom,the number of customer going bathroom plus 1*/
        addMV(numInGroupAskForBathroom[groupId]);
        Printf("Customer [%d] in Group [%d] is going to the bathroom.\n",customerId,groupId);    
        temp=getMV(answerBathroom[groupId]);
        temp1=getMV(numCustomersInGroup[groupId]);
        if(temp==temp1){
            SignalCV(lGroup[groupId], cGroup[groupId]);
        }  
        ReleaseLock(lGroup[groupId]);
	/* Yield();*/
        AcquireLock(lGroup[groupId]);
        temp = getMV(numInGroupAskForBathroom[groupId]);
        temp--;
        setMV(numInGroupAskForBathroom[groupId],temp);
        if(0==temp){
            SignalCV(lGroup[groupId], cGroup[groupId]);
        }
        ReleaseLock( lGroup[groupId]); 
        Printf("Customer [%d] in Group [%d] is going out the bathroom.\n",customerId,groupId); 
    }
    else{
        Printf("Customer [%d] in Group [%d] do not go to the bathroom.\n",customerId,groupId); 
        temp=getMV(answerBathroom[groupId]);
        temp1=getMV(numCustomersInGroup[groupId]);
        if (temp == temp1)
        {
            SignalCV(lGroup[groupId], cGroup[groupId]);
        }
        ReleaseLock(lGroup[groupId]);
    }
}

int  main()
{
    int debug;
    int customerId, groupId;
    int needBathroom;
    int i;
    int temp;
    int temp1;
    int temp2;
    Customer * current;
    initTheater();
    
    AcquireLock(cutomerNoLock);
    temp=getMV(nextCustomerId);
    customerId = temp++;
    setMV(nextCustomerId,temp);
    temp2=getMV(numGroups);
    for(i = 0; i<temp2; i++)
    {
        temp=getMV(curCustomerNumInGroup[i]);
        temp1=getMV(numCustomersInGroup[i]);
        if(temp<(temp1-1))
            break;
    }
    current=&cr[customerId];
    current->customerId=customerId;
    groupId = i;
    current->groupId=i;
    current->groupSize=temp;
    addMV(curCustomerNumInGroup[i]);
    current->groupSize=getMV(numCustomersInGroup[i]);
    ReleaseLock(cutomerNoLock);

    /* DEBUGINFO('c', "Customer [%d] in group [%d] waitTickets", customerId, groupId); */
    /* regular customer wait forhead customer to buy tickets */
    waitTickets(customerId, groupId);
    /* DEBUGINFO('c', "Customer [%d] in group [%d] waitFood", customerId, groupId); */
    /* regular customer wait forhead customer to buy Food     */
    waitFood(customerId, groupId);
    /* DEBUGINFO('c', "Customer [%d] in group [%d] waitCheck", customerId, groupId); */
    /* regular customer wait for head customer to check ticket     */
    waitCheck(customerId, groupId);
    /* DEBUGINFO('c', "Customer [%d] in group [%d] waitSeats", customerId, groupId);  */
    /* regular customer wait for head customer to arrange food */
    waitSeats(customerId, groupId);
        /* DEBUGINFO('c', "Customer [%d] in group [%d] watchMovie", customerId, groupId); */
    /* regular customer watch movie */
    watchMovie(customerId, groupId);
    /* DEBUGINFO('c', "Customer [%d] in group [%d] waitLeaveRoom", customerId, groupId); */
    /* regular customer wait for head customer to ask them to leave theater room together */
   waitLeavingmovieRoom(customerId, groupId);
   Printf("Customer [%d] in group [%d] is getting out of a theater room seat.\n",customerId,groupId);
        /* DEBUGINFO('c', "Customer [%d] in group [%d] waitBathroom", customerId, groupId); */
   waitBathroom( customerId,  groupId);
   Printf("Customer [%d] in group [%d] bathroom over\n",customerId,groupId);
   waitLeavingTheater(customerId, groupId);
   Printf("Customer [%d] in group [%d] leave the theater\n",customerId,groupId);
   AcquireLock(lCustomerLeft);	
  subMV(customerLeft); 
    ReleaseLock(lCustomerLeft);
   Exit(0);
}
/************************************************
 *
 *  end for regular customer
 *
 ************************************************/


